import {
  Injectable,
  NotFoundException,
  ForbiddenException,
  BadRequestException,
  Logger,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Not, IsNull } from 'typeorm';
import { Message, MessageType } from './entities/message.entity';
import { Notification, NotificationType } from './entities/notification.entity';
import { Conversation } from './entities/conversation.entity';
import { User } from '../auth/entities/user.entity';
import {
  Friendship,
  FriendshipStatus,
} from '../friends/entities/friendship.entity';
import { SendMessageDto } from './dto/send-message.dto';
import { CreateNotificationDto } from './dto/create-notification.dto';
import { NotificationsGateway } from '../notifications/notifications.gateway';

@Injectable()
export class MessagesService {
  private readonly logger = new Logger(MessagesService.name);

  constructor(
    @InjectRepository(Message)
    private readonly messageRepository: Repository<Message>,
    @InjectRepository(Notification)
    private readonly notificationRepository: Repository<Notification>,
    @InjectRepository(Conversation)
    private readonly conversationRepository: Repository<Conversation>,
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    @InjectRepository(Friendship)
    private readonly friendshipRepository: Repository<Friendship>,
    private readonly notificationsGateway: NotificationsGateway,
  ) {}

  // ==================== 私信消息相关 ====================

  /**
   * 发送消息
   * @param dto 发送消息DTO
   * @param senderId 发送者ID
   * @returns 发送的消息
   */
  async sendMessage(dto: SendMessageDto, senderId: number): Promise<Message> {
    const { receiverId, content, type = MessageType.TEXT, mediaUrl } = dto;

    // 不能给自己发消息
    if (receiverId === senderId) {
      throw new BadRequestException('不能给自己发消息');
    }

    // 检查接收者是否存在
    const receiver = await this.userRepository.findOne({
      where: { id: receiverId },
    });
    if (!receiver) {
      throw new NotFoundException('接收者不存在');
    }

    // 检查是否是好友
    const isFriend = await this.friendshipRepository.findOne({
      where: [
        {
          userId: senderId,
          friendId: receiverId,
          status: FriendshipStatus.ACCEPTED,
        },
        {
          userId: receiverId,
          friendId: senderId,
          status: FriendshipStatus.ACCEPTED,
        },
      ],
    });

    if (!isFriend) {
      throw new ForbiddenException('只能给好友发送消息');
    }

    // 生成会话ID
    const conversationId = Conversation.generateConversationId(
      senderId,
      receiverId,
    );

    // 创建消息
    const message = this.messageRepository.create({
      conversationId,
      senderId,
      receiverId,
      type,
      content,
      mediaUrl,
      isRead: false,
    });

    const savedMessage = await this.messageRepository.save(message);

    // 更新或创建会话
    await this.updateConversation(
      conversationId,
      senderId,
      receiverId,
      content,
    );

    // 获取发送者信息
    const sender = await this.userRepository.findOne({
      where: { id: senderId },
      select: ['id', 'username', 'nickname', 'avatar'],
    });

    // 如果接收者在线，通过 WebSocket 推送
    if (this.notificationsGateway.isUserOnline(receiverId)) {
      this.notificationsGateway.sendToUser(receiverId, 'chat-message', {
        type: 'CHAT_MESSAGE',
        messageId: savedMessage.id,
        conversationId: savedMessage.conversationId,
        sender: {
          id: sender?.id,
          username: sender?.username,
          nickname: sender?.nickname,
          avatar: sender?.avatar,
        },
        content: savedMessage.content,
        messageType: savedMessage.type,
        mediaUrl: savedMessage.mediaUrl,
        isRead: savedMessage.isRead,
        createdAt: savedMessage.createdAt,
      });
      this.logger.log(
        `已通过 WebSocket 向用户 ${receiverId} 推送聊天消息 ${savedMessage.id}`,
      );
    } else {
      this.logger.log(
        `用户 ${receiverId} 不在线，消息 ${savedMessage.id} 将在下次登录时显示`,
      );
    }

    return savedMessage;
  }

  /**
   * 更新会话信息
   * @param conversationId 会话ID
   * @param senderId 发送者ID
   * @param receiverId 接收者ID
   * @param lastMessageContent 最后一条消息内容
   */
  private async updateConversation(
    conversationId: string,
    senderId: number,
    receiverId: number,
    lastMessageContent: string,
  ): Promise<void> {
    const [user1Id, user2Id] =
      senderId < receiverId ? [senderId, receiverId] : [receiverId, senderId];

    let conversation = await this.conversationRepository.findOne({
      where: { conversationId },
    });

    if (!conversation) {
      // 创建新会话
      conversation = this.conversationRepository.create({
        conversationId,
        user1Id,
        user2Id,
        lastMessageContent,
        lastMessageAt: new Date(),
        user1UnreadCount: senderId === user1Id ? 0 : 1,
        user2UnreadCount: senderId === user2Id ? 0 : 1,
      });
    } else {
      // 更新会话
      conversation.lastMessageContent = lastMessageContent;
      conversation.lastMessageAt = new Date();

      // 增加接收者的未读计数
      if (receiverId === user1Id) {
        conversation.user1UnreadCount += 1;
      } else {
        conversation.user2UnreadCount += 1;
      }
    }

    await this.conversationRepository.save(conversation);
  }

  /**
   * 获取会话列表
   */
  async getConversations(
    userId: number,
    page: number = 1,
    limit: number = 20,
  ): Promise<{
    data: Array<any>;
    total: number;
    page: number;
    limit: number;
    totalPages: number;
  }> {
    const [conversations, total] =
      await this.conversationRepository.findAndCount({
        where: [{ user1Id: userId }, { user2Id: userId }],
        order: { lastMessageAt: 'DESC' },
        skip: (page - 1) * limit,
        take: limit,
      });

    // 获取对方用户信息
    const conversationsWithUser = await Promise.all(
      conversations.map(async (conv) => {
        const otherUserId =
          conv.user1Id === userId ? conv.user2Id : conv.user1Id;
        const otherUser = await this.userRepository.findOne({
          where: { id: otherUserId },
          select: ['id', 'username', 'email', 'avatar'],
        });

        const unreadCount =
          conv.user1Id === userId
            ? conv.user1UnreadCount
            : conv.user2UnreadCount;

        return {
          conversationId: conv.conversationId,
          otherUser,
          lastMessageContent: conv.lastMessageContent,
          lastMessageAt: conv.lastMessageAt,
          unreadCount,
          updatedAt: conv.updatedAt,
        };
      }),
    );

    return {
      data: conversationsWithUser,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 获取会话消息列表
   */
  async getConversationMessages(
    conversationId: string,
    userId: number,
    page: number = 1,
    limit: number = 50,
  ): Promise<{
    data: Message[];
    total: number;
    page: number;
    limit: number;
    totalPages: number;
  }> {
    // 验证用户是否属于该会话
    const [user1Id, user2Id] = conversationId.split('_').map(Number);
    if (userId !== user1Id && userId !== user2Id) {
      throw new ForbiddenException('无权访问该会话');
    }

    const [messages, total] = await this.messageRepository.findAndCount({
      where: {
        conversationId,
        isDeletedBySender: false,
        isDeletedByReceiver: false,
      },
      order: { createdAt: 'DESC' },
      skip: (page - 1) * limit,
      take: limit,
    });

    return {
      data: messages.reverse(), // 反转顺序，最旧的在前
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 标记消息为已读
   */
  async markMessageAsRead(messageId: number, userId: number): Promise<void> {
    const message = await this.messageRepository.findOne({
      where: { id: messageId },
    });

    if (!message) {
      throw new NotFoundException('消息不存在');
    }

    if (message.receiverId !== userId) {
      throw new ForbiddenException('只能标记自己接收的消息');
    }

    if (!message.isRead) {
      message.isRead = true;
      message.readAt = new Date();
      await this.messageRepository.save(message);

      // 更新会话未读计数
      await this.decrementUnreadCount(message.conversationId, userId);

      // 如果发送者在线，推送已读回执
      if (this.notificationsGateway.isUserOnline(message.senderId)) {
        this.notificationsGateway.sendToUser(message.senderId, 'message-read', {
          type: 'MESSAGE_READ',
          messageId: message.id,
          conversationId: message.conversationId,
          readBy: userId,
          readAt: message.readAt,
        });
        this.logger.log(
          `已通过 WebSocket 向用户 ${message.senderId} 推送消息已读回执`,
        );
      }
    }
  }

  /**
   * 标记会话所有消息为已读
   */
  async markConversationAsRead(
    conversationId: string,
    userId: number,
  ): Promise<void> {
    // 验证用户是否属于该会话
    const [user1Id, user2Id] = conversationId.split('_').map(Number);
    if (userId !== user1Id && userId !== user2Id) {
      throw new ForbiddenException('无权访问该会话');
    }

    // 更新所有未读消息
    await this.messageRepository.update(
      {
        conversationId,
        receiverId: userId,
        isRead: false,
      },
      {
        isRead: true,
        readAt: new Date(),
      },
    );

    // 重置会话未读计数
    const conversation = await this.conversationRepository.findOne({
      where: { conversationId },
    });

    if (conversation) {
      if (userId === conversation.user1Id) {
        conversation.user1UnreadCount = 0;
      } else {
        conversation.user2UnreadCount = 0;
      }
      await this.conversationRepository.save(conversation);
    }
  }

  /**
   * 减少未读计数
   */
  private async decrementUnreadCount(
    conversationId: string,
    userId: number,
  ): Promise<void> {
    const conversation = await this.conversationRepository.findOne({
      where: { conversationId },
    });

    if (conversation) {
      if (
        userId === conversation.user1Id &&
        conversation.user1UnreadCount > 0
      ) {
        conversation.user1UnreadCount -= 1;
      } else if (
        userId === conversation.user2Id &&
        conversation.user2UnreadCount > 0
      ) {
        conversation.user2UnreadCount -= 1;
      }
      await this.conversationRepository.save(conversation);
    }
  }

  /**
   * 删除消息
   */
  async deleteMessage(messageId: number, userId: number): Promise<void> {
    const message = await this.messageRepository.findOne({
      where: { id: messageId },
    });

    if (!message) {
      throw new NotFoundException('消息不存在');
    }

    // 标记删除
    if (message.senderId === userId) {
      message.isDeletedBySender = true;
    } else if (message.receiverId === userId) {
      message.isDeletedByReceiver = true;
    } else {
      throw new ForbiddenException('无权删除该消息');
    }

    await this.messageRepository.save(message);

    // 如果双方都删除了，则物理删除
    if (message.isDeletedBySender && message.isDeletedByReceiver) {
      await this.messageRepository.remove(message);
    }
  }

  /**
   * 获取未读消息总数
   */
  async getUnreadMessagesCount(userId: number): Promise<number> {
    const count = await this.messageRepository.count({
      where: {
        receiverId: userId,
        isRead: false,
        isDeletedByReceiver: false,
      },
    });

    return count;
  }

  // ==================== 系统通知相关 ====================

  /**
   * 创建通知
   */
  async createNotification(dto: CreateNotificationDto): Promise<Notification> {
    const notification = this.notificationRepository.create({
      ...dto,
      isRead: false,
    });

    return await this.notificationRepository.save(notification);
  }

  /**
   * 批量创建通知（用于系统通知多个用户）
   */
  async createNotifications(
    dtos: CreateNotificationDto[],
  ): Promise<Notification[]> {
    const notifications = dtos.map((dto) =>
      this.notificationRepository.create({
        ...dto,
        isRead: false,
      }),
    );

    return await this.notificationRepository.save(notifications);
  }

  /**
   * 获取通知列表
   */
  async getNotifications(
    userId: number,
    page: number = 1,
    limit: number = 20,
    type?: NotificationType,
  ): Promise<{
    data: Notification[];
    total: number;
    page: number;
    limit: number;
    totalPages: number;
  }> {
    const where: any = {
      userId,
      isDeleted: false,
    };

    if (type) {
      where.type = type;
    }

    const [notifications, total] =
      await this.notificationRepository.findAndCount({
        where,
        order: { createdAt: 'DESC' },
        skip: (page - 1) * limit,
        take: limit,
      });

    return {
      data: notifications,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 标记通知为已读
   */
  async markNotificationAsRead(
    notificationId: number,
    userId: number,
  ): Promise<void> {
    const notification = await this.notificationRepository.findOne({
      where: { id: notificationId },
    });

    if (!notification) {
      throw new NotFoundException('通知不存在');
    }

    if (notification.userId !== userId) {
      throw new ForbiddenException('无权操作该通知');
    }

    if (!notification.isRead) {
      notification.isRead = true;
      notification.readAt = new Date();
      await this.notificationRepository.save(notification);
    }
  }

  /**
   * 标记所有通知为已读
   */
  async markAllNotificationsAsRead(userId: number): Promise<void> {
    await this.notificationRepository.update(
      {
        userId,
        isRead: false,
        isDeleted: false,
      },
      {
        isRead: true,
        readAt: new Date(),
      },
    );
  }

  /**
   * 删除通知
   */
  async deleteNotification(
    notificationId: number,
    userId: number,
  ): Promise<void> {
    const notification = await this.notificationRepository.findOne({
      where: { id: notificationId },
    });

    if (!notification) {
      throw new NotFoundException('通知不存在');
    }

    if (notification.userId !== userId) {
      throw new ForbiddenException('无权删除该通知');
    }

    notification.isDeleted = true;
    await this.notificationRepository.save(notification);
  }

  /**
   * 获取未读通知总数
   */
  async getUnreadNotificationsCount(userId: number): Promise<number> {
    const count = await this.notificationRepository.count({
      where: {
        userId,
        isRead: false,
        isDeleted: false,
      },
    });

    return count;
  }

  /**
   * 清空所有通知
   */
  async clearAllNotifications(userId: number): Promise<void> {
    await this.notificationRepository.update(
      {
        userId,
        isDeleted: false,
      },
      {
        isDeleted: true,
      },
    );
  }
}
